package com.sparrow.event.core;

import com.google.common.base.Preconditions;
import com.sparrow.common.event.IEventInvoker;
import com.sparrow.common.thread.IdExecutorGroup;
import com.sparrow.common.thread.factory.SimpleThreadFactory;
import com.sparrow.common.util.ByteBuddyUtil;
import com.sparrow.event.api.EventBus;
import com.sparrow.event.model.Event;
import com.sparrow.event.invoke.impl.ReflectEventInvoker;
import com.sparrow.event.receiver.IEventReceiver;
import com.sparrow.event.receiver.impl.EventActor;
import com.sparrow.event.receiver.impl.EventReceiver;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * 事件总线实现
 */
public class EventBusImpl implements EventBus, DisposableBean {
    private static Logger logger = LoggerFactory.getLogger(EventBusImpl.class);

    /**
     * 事件接受者映射，键为事件类型，值为对应的事件接收者列表
     */
    private final Map<Class<?>, List<IEventReceiver>> receiverMap = new HashMap<>();
    /**
     * id线程池
     */
    private final IdExecutorGroup idExecutorGroup;
    /**
     * 事件actor
     */
    private EventActor actor;

    private ExecutorService defaultEventExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("event-default"));

    public EventBusImpl(IdExecutorGroup idExecutorGroup) {
        this.idExecutorGroup = idExecutorGroup;
        this.actor = new EventActor(defaultEventExecutor);
    }

    /**
     * 注册事件接收者
     *
     * @param bean 带有事件接收方法的对象
     * @param method 事件接收方法
     */
    public synchronized void register(Object bean, Method method) {
        com.sparrow.event.annotation.EventReceiver annotation = method.getAnnotation(com.sparrow.event.annotation.EventReceiver.class);
        Preconditions.checkNotNull(annotation, "EventReceiver annotation cannot be null");

        Class<?> eventClass = getEventClassFromMethod(method);
        try {
            int order = annotation.order();
            IEventInvoker eventInvoker = ByteBuddyUtil.generateInvoker(bean.getClass(), method, bean);
            registerEventReceiver(eventClass, new EventReceiver(eventInvoker, order));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void registerEventReceiver(Class<?> eventClass, IEventReceiver eventReceiver) {
        List<IEventReceiver> receivers = receiverMap.computeIfAbsent(eventClass, key -> new ArrayList<>());
        receivers.add(eventReceiver);
        receivers.sort(Comparator.comparingInt(IEventReceiver::getOrder));
    }

    public List<IEventReceiver> getReceivers(Class<?> eventClass) {
        return receiverMap.get(eventClass);
    }

    public void walkInvokers(Class<?> eventClass, Consumer<IEventInvoker> consumer) {
        List<IEventReceiver> receivers = receiverMap.get(eventClass);
        for (IEventReceiver receiver : receivers) {
            consumer.accept(receiver.getInvoker());
        }
    }

    /**
     * 从方法的参数中获取事件类型，当方法有多个参数时候约定最后一个参数为事件
     *
     * @param method 事件接收方法
     * @return 事件类型
     */
    private Class<?> getEventClassFromMethod(Method method) {
        Class<?>[] parameterTypes = method.getParameterTypes();
        Preconditions.checkArgument(parameterTypes.length > 0, "Event method must have at least one parameter");
        return parameterTypes[parameterTypes.length - 1];
    }

    /**
     * 创建事件接收者实例
     *
     * @param object 带有事件接收方法的对象
     * @param method 事件接收方法
     * @param order
     * @return 事件接收者实例
     */
    private IEventReceiver createEventReceiver(Object object, Method method, int order) {
        return new EventReceiver(createReflectInvoker(object, method), order);
    }

    public ReflectEventInvoker createReflectInvoker(Object object, Method method) {
        return new ReflectEventInvoker(object, method);
    }

    /**
     * 发布事件
     *
     * @param event 要发布的事件
     */
    @Override
    public void publish(Event event) {
        actor.tell(() -> {
            receive(event, getReceiversForEvent(event));
        }, getExecutor(event), event.isSync());
    }

    private Executor getExecutor(Event event) {
        Executor executor = null;
        if (!event.isSync()) {
            if (event.getExecutor() != null) {
                executor = event.getExecutor();
            } else {
                executor = idExecutorGroup.takeExecutor(event.getDispatchCode());
            }
        }
        return executor;
    }

    /**
     * 获取事件对应的接收者列表
     *
     * @param event 事件
     * @return 接收者列表
     */
    private List<IEventReceiver> getReceiversForEvent(Event event) {
        return receiverMap.get(event.getObj().getClass());
    }

    /**
     * 处理事件接收逻辑
     *
     * @param event     事件
     * @param receivers 事件接收者列表
     */
    private void receive(Event event, List<IEventReceiver> receivers) {
        if (receivers == null || receivers.size() == 0) {
            return;
        }
        if (event.getDirectRun() != null) {
            event.getDirectRun().run();
            return;
        }
        for (IEventReceiver receiver : receivers) {
            try {
                receiver.receive(event);
            } catch (Exception e) {
                handleReceiverException(receiver, event, e);
            }
        }
    }

    /**
     * 处理事件接收过程中抛出的异常
     *
     * @param receiver 事件接收者
     * @param event    事件
     * @param e        异常
     */
    private void handleReceiverException(IEventReceiver receiver, Event event, Exception e) {
        // 这里可以添加更复杂的异常处理逻辑，如日志记录、重试机制等
        throw new RuntimeException("Error receiving event className=" + event.getObj().getClass().getSimpleName(), e);
    }

    @Override
    public void destroy() throws Exception {
        defaultEventExecutor.shutdown();
        defaultEventExecutor.awaitTermination(120, TimeUnit.SECONDS);
        logger.info("eventBus关闭");
    }


}